<template>
  <div class="batch-prediction-container">
    <!-- 页面标题 -->
    <div class="page-header">
      <div class="page-title">批量预测</div>
      <div class="header-actions">
        <el-button type="success" @click="loadAvailableModels">刷新模型</el-button>
        <el-button type="primary" @click="clearAll">清空记录</el-button>
      </div>
    </div>

    <!-- 上传和配置区域 -->
    <el-card class="upload-card" shadow="hover">
      <template #header>
        <div class="card-header">
          <span>数据上传与配置</span>
        </div>
      </template>
      <el-row :gutter="20">
        <el-col :xs="24" :sm="24" :md="12" :lg="10" :xl="8">
          <!-- 文件上传 -->
          <div class="upload-area">
            <el-upload
              class="upload-component"
              drag
              action="#"
              :auto-upload="false"
              :show-file-list="false"
              :on-change="handleFileChange"
              :before-upload="beforeUpload"
              accept=".csv,.xlsx,.xls"
            >
              <el-icon class="el-icon-upload"><i class="el-icon-upload"></i></el-icon>
              <div class="upload-text">将文件拖到此处，或<em>点击上传</em></div>
              <div class="upload-hint">支持 .csv 格式 (推荐), .xlsx, .xls 格式</div>
            </el-upload>
            
            <div class="selected-file" v-if="selectedFile">
              <div class="file-info">
                <i class="el-icon-document"></i>
                <span class="file-name">{{ selectedFile.name }}</span>
              </div>
              <div class="file-actions">
                <el-button size="small" type="danger" @click="removeFile">移除</el-button>
              </div>
            </div>
          </div>
        </el-col>
        
        <el-col :xs="24" :sm="24" :md="12" :lg="14" :xl="16">
          <!-- 预测配置 -->
          <div class="prediction-config">
            <h3>预测配置</h3>
            <el-form :model="predictionConfig" label-width="120px">
              <el-form-item label="预测模型">
                <el-select v-model="predictionConfig.model" style="width: 100%" :loading="loading">
                  <el-option 
                    v-for="model in availableModels" 
                    :key="model.id" 
                    :label="`${model.name} (准确率: ${(model.accuracy * 100).toFixed(2)}%${model.is_active ? ' - 当前活跃' : ''})`" 
                    :value="model.id">
                    <span>{{ model.name }}</span>
                    <span style="float: right; color: #8492a6; font-size: 13px">
                      {{ model.type }} | {{ (model.accuracy * 100).toFixed(2) }}%
                      <el-tag v-if="model.is_active" size="small" type="success">活跃</el-tag>
                    </span>
                  </el-option>
                </el-select>
              </el-form-item>
              
              <el-form-item label="风险阈值">
                <el-slider
                  v-model="predictionConfig.threshold"
                  :step="0.01"
                  :min="0"
                  :max="1"
                  show-input
                  show-stops
                  :marks="thresholdMarks"
                ></el-slider>
              </el-form-item>
              
              <el-form-item label="结果处理">
                <el-checkbox-group v-model="predictionConfig.actions">
                  <el-checkbox label="export">导出预测结果</el-checkbox>
                  <el-checkbox label="save">保存到系统</el-checkbox>
                  <el-checkbox label="alert">创建预警</el-checkbox>
                </el-checkbox-group>
              </el-form-item>
              
              <el-form-item>
                <el-button type="primary" :disabled="!selectedFile" @click="runPrediction">
                  开始预测
                </el-button>
              </el-form-item>
            </el-form>
          </div>
        </el-col>
      </el-row>
    </el-card>

    <!-- 数据预览区域 -->
    <el-card class="preview-card" shadow="hover" v-if="tableData.length > 0">
      <template #header>
        <div class="card-header">
          <span>数据预览</span>
          <span class="data-count">共 {{ tableData.length }} 条记录</span>
        </div>
      </template>
      <el-table
        :data="tableData.slice(0, 10)"
        border
        style="width: 100%"
        max-height="300"
        :header-cell-style="{ background: '#f5f7fa' }"
      >
        <el-table-column
          v-for="(column, index) in tableColumns"
          :key="index"
          :prop="column"
          :label="column"
          :width="column === 'customerID' ? '150' : ''"
        ></el-table-column>
      </el-table>
      <div class="preview-note" v-if="tableData.length > 10">
        <i class="el-icon-info"></i>
        <span>仅显示前10条记录</span>
      </div>
    </el-card>

    <!-- 预测结果区域 -->
    <el-card class="result-card" shadow="hover" v-if="predictionResults.length > 0">
      <template #header>
        <div class="card-header">
          <span>预测结果</span>
          <div class="header-actions">
            <el-button size="small" type="success" @click="exportResults">导出结果</el-button>
            <el-button size="small" type="primary" @click="saveResults">保存结果</el-button>
          </div>
        </div>
      </template>
      
      <!-- 结果统计 -->
      <div class="result-stats">
        <div class="stat-card">
          <div class="stat-value">{{ predictionSummary.totalCustomers }}</div>
          <div class="stat-label">总客户数</div>
        </div>
        <div class="stat-card">
          <div class="stat-value">{{ predictionSummary.highRiskCount }}</div>
          <div class="stat-label">高风险客户</div>
          <div class="stat-percent">({{ predictionSummary.highRiskPercent }}%)</div>
        </div>
        <div class="stat-card">
          <div class="stat-value">{{ predictionSummary.mediumRiskCount }}</div>
          <div class="stat-label">中风险客户</div>
          <div class="stat-percent">({{ predictionSummary.mediumRiskPercent }}%)</div>
        </div>
        <div class="stat-card">
          <div class="stat-value">{{ predictionSummary.lowRiskCount }}</div>
          <div class="stat-label">低风险客户</div>
          <div class="stat-percent">({{ predictionSummary.lowRiskPercent }}%)</div>
        </div>
      </div>
      
      <!-- 预测结果表格 -->
      <el-table
        v-if="showResults"
        v-loading="predicting"
        :data="paginatedTableData"
        border
        style="width: 100%"
      >
        <el-table-column prop="customerID" label="客户ID" min-width="120" />
        <el-table-column label="流失概率" width="120">
          <template #default="scope">
            {{ (scope.row.probability * 100).toFixed(2) }}%
          </template>
        </el-table-column>
        <el-table-column label="流失风险" width="100">
          <template #default="scope">
            <el-tag
              :type="getRiskLevelType(scope.row.riskLevel)"
              :effect="scope.row.label ? 'dark' : 'light'"
            >
              {{ getRiskLevelText(scope.row.riskLevel) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="mainFactors" label="主要风险因素"></el-table-column>
        <el-table-column label="操作" width="200" fixed="right">
          <template #default="scope">
            <el-button size="small" @click="viewCustomerDetail(scope.row)">查看详情</el-button>
            <el-button size="small" type="primary" @click="createAlert(scope.row)">创建预警</el-button>
          </template>
        </el-table-column>
      </el-table>
      
      <!-- 分页控件 -->
      <div class="pagination-container">
        <el-pagination
          background
          layout="prev, pager, next, sizes"
          :page-sizes="[10, 20, 50, 100]"
          :page-size="pageSize"
          :current-page="currentPage"
          :total="predictionResults.length"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        ></el-pagination>
      </div>
    </el-card>
    
    <!-- 处理结果对话框 -->
    <el-dialog title="预测结果处理" v-model="resultDialogVisible" width="30%">
      <div class="result-dialog-content">
        <i class="el-icon-success"></i>
        <h2>处理完成</h2>
        <p>批量预测已完成，共处理了 {{ predictionResults.length }} 条数据。</p>
        <p>
          <span>高风险客户：</span>
          <span class="highlight">{{ predictionSummary.highRiskCount }} 人</span>
        </p>
        <p>
          <span>中风险客户：</span>
          <span class="highlight">{{ predictionSummary.mediumRiskCount }} 人</span>
        </p>
        <p>
          <span>低风险客户：</span>
          <span class="highlight">{{ predictionSummary.lowRiskCount }} 人</span>
        </p>
      </div>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="resultDialogVisible = false">关闭</el-button>
          <el-button type="primary" @click="saveResults">保存结果</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { predictBatchCustomers, savePredictionResult, createChurnAlert, getAvailableModels } from '@/api/modules/prediction'

const router = useRouter()

// 文件上传相关
const selectedFile = ref(null)

// 预测配置
const predictionConfig = reactive({
  model: '',
  threshold: 0.5,
  actions: ['export']
})

// 可用的模型列表
const availableModels = ref([])
const loading = ref(false)

// 加载可用的模型列表
const loadAvailableModels = async () => {
  try {
    loading.value = true
    const response = await getAvailableModels()
    if (response) {
      // API已经返回了正确的模型格式，直接使用
      availableModels.value = response
      
      // 如果有可用模型，默认选择第一个
      if (availableModels.value.length > 0) {
        predictionConfig.model = availableModels.value[0].id
      }
    } else {
      throw new Error('获取模型列表失败')
    }
  } catch (error) {
    ElMessage.error(`获取模型列表失败: ${error.message || '未知错误'}`)
    console.error('获取模型列表错误:', error)
    // 提供一些默认模型，以防API调用失败
    availableModels.value = [
      { id: 'ensemble', name: '默认融合模型 (推荐)', type: 'Ensemble', accuracy: 0.85, is_active: true },
      { id: 'random_forest', name: '随机森林模型', type: 'Random Forest', accuracy: 0.82, is_active: false },
      { id: 'xgboost', name: 'XGBoost模型', type: 'XGBoost', accuracy: 0.83, is_active: false },
      { id: 'logistic', name: '逻辑回归模型', type: 'Logistic Regression', accuracy: 0.81, is_active: false }
    ]
    predictionConfig.model = 'ensemble'
  } finally {
    loading.value = false
  }
}

// 在组件挂载时加载模型列表
onMounted(() => {
  loadAvailableModels()
})

// 阈值标记
const thresholdMarks = {
  0: '0',
  0.25: '0.25',
  0.5: '0.5',
  0.75: '0.75',
  1: '1'
}

// 表格数据
const tableData = ref([])
const tableColumns = ref([])

// 预测结果
const predictionResults = ref([])
const resultDialogVisible = ref(false)

// 分页相关
const pageSize = ref(10)
const currentPage = ref(1)

// 格式化日期时间
const formatDateTime = (date) => {
  const year = date.getFullYear()
  const month = String(date.getMonth() + 1).padStart(2, '0')
  const day = String(date.getDate()).padStart(2, '0')
  const hours = String(date.getHours()).padStart(2, '0')
  const minutes = String(date.getMinutes()).padStart(2, '0')
  const seconds = String(date.getSeconds()).padStart(2, '0')
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}

// 处理文件上传
const handleFileChange = (file) => {
  if (file) {
    selectedFile.value = file.raw
    // 解析CSV文件
    parseFile(file.raw)
  }
}

// 文件上传前的验证
const beforeUpload = (file) => {
  const isCSV = file.type === 'text/csv' || file.name.endsWith('.csv')
  const isExcel = file.type === 'application/vnd.ms-excel' || 
                 file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
                 file.name.endsWith('.xlsx') || 
                 file.name.endsWith('.xls')
  
  if (!isCSV && !isExcel) {
    ElMessage.error('只能上传CSV或Excel文件!')
    return false
  }
  
  const isLt10M = file.size / 1024 / 1024 < 10
  if (!isLt10M) {
    ElMessage.error('文件大小不能超过10MB!')
    return false
  }
  
  return true
}

// 解析文件
const parseFile = (file) => {
  const reader = new FileReader()
  
  reader.onload = (e) => {
    const fileContent = e.target.result
    try {
      // 根据文件类型选择不同的解析方法
      if (file.name.endsWith('.csv')) {
        parseCSV(fileContent)
      } else if (file.name.endsWith('.xlsx') || file.name.endsWith('.xls')) {
        ElMessage.error('Excel文件解析功能尚未实现，请使用CSV格式')
      } else {
        ElMessage.error('不支持的文件格式')
      }
    } catch (error) {
      ElMessage.error(`文件解析失败: ${error.message}`)
      console.error('解析错误:', error)
    }
  }
  
  reader.onerror = () => {
    ElMessage.error('文件读取失败')
  }
  
  // 以文本形式读取文件
  reader.readAsText(file)
}

// 解析CSV文件
const parseCSV = (csvContent) => {
  // 简单的CSV解析逻辑
  const lines = csvContent.split('\n')
  if (lines.length === 0) {
    ElMessage.error('文件为空')
    return
  }
  
  // 提取列名（表头）
  const headers = lines[0].split(',').map(header => header.trim())
  tableColumns.value = headers
  
  // 解析数据行
  const data = []
  for (let i = 1; i < lines.length; i++) {
    const line = lines[i].trim()
    if (!line) continue // 跳过空行
    
    const values = line.split(',')
    if (values.length !== headers.length) {
      console.warn(`第${i+1}行数据列数不匹配，已跳过`)
      continue
    }
    
    const customer = {}
    headers.forEach((header, index) => {
      customer[header] = values[index].trim()
    })
    
    data.push(customer)
  }
  
  tableData.value = data
  
  ElMessage({
    message: `成功解析文件，共 ${tableData.value.length} 条记录`,
    type: 'success'
  })
}

// 移除文件
const removeFile = () => {
  selectedFile.value = null
  tableData.value = []
  tableColumns.value = []
  predictionResults.value = []
}

// 运行预测
const runPrediction = async () => {
  if (!selectedFile.value) {
    ElMessage.warning('请先上传数据文件')
    return
  }
  
  ElMessage({
    message: '正在进行预测分析，请稍候...',
    type: 'info',
    duration: 2000
  })
  
  try {
    // 准备要发送的数据
    const requestData = {
      customers: tableData.value,
      model: predictionConfig.model,
      threshold: predictionConfig.threshold
    }
    
    // 调用API进行批量预测
    const response = await predictBatchCustomers(requestData)
    
    if (response && response.code === 200) {
      // 更新预测结果
      predictionResults.value = response.data.results || []
      
      // 显示结果对话框
      resultDialogVisible.value = true
      
      ElMessage({
        message: response.message || '批量预测完成',
        type: 'success'
      })
    } else {
      throw new Error(response.error || '批量预测失败')
    }
  } catch (error) {
    ElMessage.error(`批量预测失败: ${error.message || '未知错误'}`)
    console.error('批量预测错误:', error)
  }
}

// 查看客户详情
const viewCustomerDetail = (row) => {
  router.push(`/customer/detail/${row.customerId}`)
}

// 创建预警
const createAlert = async (row) => {
  try {
    // 准备预警数据
    const alertData = {
      customerId: row.customerId,
      predictionTime: formatDateTime(new Date()),
      probability: row.churnProbability,
      riskLevel: row.riskLevel,
      mainFactors: row.mainFactors
    }
    
    // 调用API创建预警
    const response = await createChurnAlert(alertData)
    
    if (response && response.code === 200) {
      ElMessage({
        message: `已为客户 ${row.customerId} 创建流失预警`,
        type: 'success'
      })
    } else {
      throw new Error(response.message || '创建预警失败')
    }
  } catch (error) {
    ElMessage.error(`创建预警失败: ${error.message || '未知错误'}`)
    console.error('创建预警错误:', error)
  }
}

// 导出结果
const exportResults = () => {
  if (predictionResults.value.length === 0) {
    ElMessage.warning('没有可导出的预测结果')
    return
  }
  
  ElMessage({
    message: '正在导出预测结果，请稍候...',
    type: 'info'
  })
  
  try {
    // 准备CSV数据
    let csvContent = 'data:text/csv;charset=utf-8,'
    
    // 添加CSV标题行
    csvContent += '客户ID,流失概率,风险等级,主要风险因素\n'
    
    // 添加数据行
    predictionResults.value.forEach(row => {
      const probability = (row.churnProbability * 100).toFixed(2) + '%'
      const riskLevel = row.riskLevel === 'high' ? '高风险' : (row.riskLevel === 'medium' ? '中风险' : '低风险')
      csvContent += `${row.customerId},${probability},${riskLevel},${row.mainFactors}\n`
    })
    
    // 创建下载链接
    const encodedUri = encodeURI(csvContent)
    const link = document.createElement('a')
    link.setAttribute('href', encodedUri)
    link.setAttribute('download', `批量预测结果_${formatDateTime(new Date()).replace(/[: -]/g, '_')}.csv`)
    document.body.appendChild(link)
    
    // 触发下载
    link.click()
    
    ElMessage({
      message: '预测结果已导出成功',
      type: 'success'
    })
  } catch (error) {
    ElMessage.error(`导出失败: ${error.message || '未知错误'}`)
    console.error('导出错误:', error)
  }
}

// 保存结果
const saveResults = async () => {
  ElMessage({
    message: '正在保存预测结果到系统，请稍候...',
    type: 'info'
  })
  
  try {
    // 准备保存数据
    const saveData = {
      batchId: 'BATCH-' + Date.now(),
      predictionTime: formatDateTime(new Date()),
      model: predictionConfig.model,
      threshold: predictionConfig.threshold,
      results: predictionResults.value
    }
    
    // 调用API保存预测结果
    const response = await savePredictionResult(saveData)
    
    if (response && response.code === 200) {
      ElMessage({
        message: '预测结果已成功保存到系统',
        type: 'success'
      })
      resultDialogVisible.value = false
    } else {
      throw new Error(response.message || '保存失败')
    }
  } catch (error) {
    ElMessage.error(`保存失败: ${error.message || '未知错误'}`)
    console.error('保存错误:', error)
  }
}

// 清空所有数据
const clearAll = () => {
  selectedFile.value = null
  tableData.value = []
  tableColumns.value = []
  predictionResults.value = []
  resultDialogVisible.value = false
}



// 分页处理
const handleSizeChange = (size) => {
  pageSize.value = size
}

const handleCurrentChange = (page) => {
  currentPage.value = page
}

// 计算预测结果摘要
const predictionSummary = computed(() => {
  const total = predictionResults.value.length
  const highRiskCount = predictionResults.value.filter(r => r.riskLevel === 'high').length
  const mediumRiskCount = predictionResults.value.filter(r => r.riskLevel === 'medium').length
  const lowRiskCount = predictionResults.value.filter(r => r.riskLevel === 'low').length
  
  return {
    totalCustomers: total,
    highRiskCount,
    mediumRiskCount,
    lowRiskCount,
    highRiskPercent: total ? Math.round((highRiskCount / total) * 100) : 0,
    mediumRiskPercent: total ? Math.round((mediumRiskCount / total) * 100) : 0,
    lowRiskPercent: total ? Math.round((lowRiskCount / total) * 100) : 0
  }
})
</script>

<style lang="scss" scoped>
.batch-prediction-container {
  padding: 20px;
  
  .page-header {
    display: flex;
    justify-content: space-between;
    margin-bottom: 20px;
    align-items: center;
    
    .page-title {
      font-size: 22px;
      font-weight: bold;
    }
  }
  
  .upload-card, .preview-card, .result-card {
    margin-bottom: 20px;
    
    .card-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      
      .data-count {
        color: #909399;
        font-size: 14px;
      }
    }
  }
  
  .upload-area {
    min-height: 280px;
    display: flex;
    flex-direction: column;
    
    .upload-component {
      flex: 1;
      display: flex;
      
      :deep(.el-upload) {
        width: 100%;
      }
      
      :deep(.el-upload-dragger) {
        width: 100%;
        height: 200px;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
      }
    }
    
    .upload-text {
      margin: 10px 0;
      
      em {
        color: #409EFF;
        font-style: normal;
        cursor: pointer;
      }
    }
    
    .upload-hint {
      font-size: 12px;
      color: #909399;
    }
    
    .selected-file {
      margin-top: 15px;
      padding: 10px;
      border: 1px dashed #d9d9d9;
      border-radius: 4px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      
      .file-info {
        display: flex;
        align-items: center;
        
        i {
          margin-right: 10px;
          color: #909399;
        }
        
        .file-name {
          font-size: 14px;
          color: #606266;
          word-break: break-all;
        }
      }
    }
  }
  
  .prediction-config {
    padding: 0 20px;
    
    h3 {
      margin-top: 0;
      margin-bottom: 20px;
      font-weight: normal;
      color: #606266;
    }
  }
  
  .preview-note {
    margin-top: 10px;
    font-size: 12px;
    color: #909399;
    display: flex;
    align-items: center;
    
    i {
      margin-right: 5px;
    }
  }
  
  .result-stats {
    display: flex;
    margin-bottom: 20px;
    flex-wrap: wrap;
    gap: 15px;
    
    .stat-card {
      flex: 1;
      min-width: 150px;
      padding: 15px;
      border-radius: 4px;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      text-align: center;
      
      &:nth-child(1) {
        background-color: #ecf5ff;
      }
      
      &:nth-child(2) {
        background-color: #fef0f0;
      }
      
      &:nth-child(3) {
        background-color: #fdf6ec;
      }
      
      &:nth-child(4) {
        background-color: #f0f9eb;
      }
      
      .stat-value {
        font-size: 24px;
        font-weight: bold;
        margin-bottom: 5px;
      }
      
      .stat-label {
        color: #606266;
        font-size: 14px;
      }
      
      .stat-percent {
        font-size: 12px;
        color: #909399;
      }
    }
  }
  
  .pagination-container {
    margin-top: 20px;
    display: flex;
    justify-content: flex-end;
  }
  
  .result-dialog-content {
    text-align: center;
    
    i {
      font-size: 50px;
      color: #67c23a;
      margin-bottom: 20px;
    }
    
    h2 {
      margin-bottom: 20px;
    }
    
    p {
      margin: 10px 0;
      text-align: left;
    }
    
    .highlight {
      color: #409EFF;
      font-weight: bold;
    }
  }
}
</style> 